//
// ShaderEffect.cpp
//

#include "ShaderEffect.h"
#include "Graphics.h"

CShaderEffect::CShaderEffect(void)
	: _type(ShaderType_Unloaded), _pConstant(0)
{
}

CShaderEffect::~CShaderEffect(void)
{
	unload();
}

// Recognize shaders with header [FUNCNAME:SHADER_VERSION].
bool CShaderEffect::load(CGraphics *pGraphics, void *pShader, size_t uLength)
{
	char *pStr;
	char func[64], profile[64];
	int count;
	LPD3DXBUFFER pCompiled, pErrmsg;

	if(_type != ShaderType_Unloaded) {
		LOG_WRITE(DS_MULTIPLE_SHADER_LOAD);
		unload();
	}

	pStr = (char *)pShader;
	while(*pStr && *pStr != '[') pStr++;
	count = 0;
	while(*pStr && *pStr != ':') func[count++] = *pStr++;
	func[count] = '\0';
	count = 0;
	while(*pStr && *pStr != ']') profile[count++] = *pStr++;
	profile[count] = '\0';

	if(*pStr == '\0') {
		LOG_WRITE(DS_INCOMPLETE_SHADER_HEADER);
		return false;
	}

	HRESULT hr = ::D3DXCompileShader((char *)pShader, uLength,
		NULL, NULL, func, profile, 0, &pCompiled, &pErrmsg, &_pConstant);
	if(FAILED(hr)) {
		if(pErrmsg) {
			wchar_t convbuf[256];
			_snwprintf(convbuf, 256, L"%S", (char *)pErrmsg->GetBufferPointer());
			LOG_WRITE(convbuf);
			pErrmsg->Release();
		}
		LOG_WRITE(DS_SHADER_COMPILE_FAILED);
		return false;
	}

	LPDIRECT3DDEVICE9 device = pGraphics->getDeviceInterface();
	switch(profile[0])
	{
	case 'p':
	case 'P':
		hr = device->CreatePixelShader((DWORD *)pCompiled->GetBufferPointer(), &_pPixelShader);
		if(FAILED(hr)) {
			LOG_WRITE(DS_CREATE_PS_FAILED, hr);
			pCompiled->Release();
			return false;
		}
		_type = ShaderType_PixelShader;
		break;
	case 'v':
	case 'V':
		hr = device->CreateVertexShader((DWORD *)pCompiled->GetBufferPointer(), &_pVertexShader);
		if(FAILED(hr)) {
			LOG_WRITE(DS_CREATE_VS_FAILED, hr);
			pCompiled->Release();
			return false;
		}
		_type = ShaderType_VertexShader;
		break;
	default:
		LOG_WRITE(DS_UNKNOWN_SHADER_TYPE, profile);
		pCompiled->Release();
		return false;
	}
	return true;
}

void CShaderEffect::unload(void)
{
	if(_type != ShaderType_Unloaded) {
		switch(_type)
		{
		case ShaderType_PixelShader:
			ReleasePixelShader(_pPixelShader);
			break;
		case ShaderType_VertexShader:
			ReleaseVertexShader(_pVertexShader);
			break;
		}
		_pConstant->Release();
		_pConstant = NULL;
		_type = ShaderType_Unloaded;
	}
}

SHADER_VAR CShaderEffect::getVariableHandle(const char *pszVariableName)
{
	return _pConstant->GetConstantByName(NULL, pszVariableName);
}

UINT CShaderEffect::getTextureRegisterByName(const char *pszVariableName)
{
	return getTextureRegister(getVariableHandle(pszVariableName));
}

UINT CShaderEffect::getTextureRegister(SHADER_VAR hVariable)
{
	D3DXCONSTANT_DESC desc;
	UINT count;
	if(hVariable == NULL) return 0;
	_pConstant->GetConstantDesc(hVariable, &desc, &count);
	return desc.RegisterIndex;
}

